/**
 * 等待者对象
 * 
 * 三个数组：监控对象容器、成功回调函数容器、失败回调函数容器
 * 监控对象：
 *      属性：监控解决成功状态、监控解决失败状态
 *      方法：解决成功方法、解决失败方法
 *      私有方法：_exec处理成功失败回调函数的方法
 *      共有方法：when监控异步逻辑
 *               done添加成功回调函数
 *               fail添加失败回调函数
 */
var Waiter = function() {
    var dfd = [],//注册了的等待对象容器
        doneArr = [],//成功回调方法容器
        failArr = [],//失败回调方法容器
        slice = Array.prototype.slice,//缓存Array方法slice
        that = this;//保存当前等待者对象
    //监控对象类
    var Primise = function() {
        this.resolved = false;//监控对象是否解决成功状态
        this.rejected = false;//监控对象是否解决失败状态
    }
    //监控对象类原型方法
    Primise.prototype = {
        //解决成功
        resolve: function() {
            this.resolved = true;
            if(!dfd.length) return;//没有监控对象则取消执行
            for(var i = dfd.length - 1; i >= 0; i--) {//如果有任意一个监控对象没有解决或者解决失败则返回
                if (dfd[i] && !dfd[i].resolved || dfd[i].rejected) return;
                dfd.splice(i, 1);//清除监控对象
            }
            _exec(doneArr);//执行解决成功回调方法
        },
        //解决失败
        reject: function() {
            this.rejected = true;
            if (!dfd.length) return;
            dfd.splice(0);
            _exec(failArr);
        }
    };
    //创建监控对象
    that.Deferred = function() {
        return new Primise();
    }
    //回调执行方法
    function _exec(arr) {
        var i = 0,
            len = arr.length;
        for(; i < len; i++) {
            try {
                arr[i] && arr[i]();
            } catch (error) {
                
            }
        }
    }
    //监控异步方法，参数，监控对象
    that.when = function() {
        // 设置监控对象
        dfd = slice.call(arguments);
        // 获取监控对象数组长度
        var i = dfd.length;
        // 向前遍历监控对象，最后一个监控对象索引值为length - 1
        for(--i; i >= 0; i--) {
            // 如果不存在监控对象，或者监控对象已经解决，或者不是监控对象
            if (!dfd[i] || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof Primise) {
                dfd.splice(i, 1);//清理内存，清除当前监控对象
            }
        }
        // 返回等待者对象
        return that;
    };
    //解决成功回调函数添加方法
    that.done = function() {
        doneArr = doneArr.concat(slice.call(arguments));
        return that;
    }
    //解决失败回调函数添加方法
    that.fail = function() {
        failArr = failArr.concat(slice.call(arguments));
        return that;
    }
}

// 34-8,测试代码
var waiter = new Waiter();

var first = function() {
    var dtd = waiter.Deferred();
    setTimeout(function() {
        console.log('first finish');
        dtd.resolve();
    }, 5000);
    return dtd;
}();

var second = function() {
    var dtd = waiter.Deferred();
    setTimeout(function() {
        console.log('second finish')
        dtd.resolve();
    });
    return dtd;
}();

waiter
    .when(first, second)
    .done(function() {
        console.log('success');
    }, function() {
        console.log('success again')
    })
    .fail(function() {
        console.log('fail');
    })
